import { createAction, createReducer, ActionType, createAsyncAction } from 'typesafe-actions';
import { Dispatch } from 'redux';
import Axios from 'axios';
import _ from 'lodash';

export interface WordGroupInitDto {
    relationId: number;
    groupId: number;
    word?: string;
}
export interface WordUserRelationIndexDto {
    id: number
    word: string
    typeValue: string
    typeId: number
    groupId?: number//用于传递state
}

export interface WordUserRelationGroupIndexDto {
    relationDtos: WordUserRelationIndexDto[]
    id: number;
}

export interface WordUserRelationDto {
    groupDtos: WordUserRelationGroupIndexDto[]
}

export interface WordUserRelationState {
    dto: WordUserRelationDto
};

const setState = createAction('WORD_USER_RELATION/REFRESH')<WordUserRelationState>();

const fetchActions = createAsyncAction(
    'WORD_USER_RELATION/FETCH/REQUEST',
    ['WORD_USER_RELATION/FETCH/SUCCESS', (res: WordUserRelationDto) => res],
    ['WORD_USER_RELATION/FETCH/FAILURE', (err: Error) => err],
    'WORD_USER_RELATION/FETCH/CANCEL',
)();
const initActions = createAsyncAction(
    'WORD_USER_RELATION/INIT/REQUEST',
    ['WORD_USER_RELATION/INIT/SUCCESS', (res: WordGroupInitDto, wordValue: string) => {
        res.word = wordValue
        return res
    }],
    ['WORD_USER_RELATION/INIT/FAILURE', (err: Error) => err],
    'WORD_USER_RELATION/INIT/CANCEL',
)();
const addActions = createAsyncAction(
    'WORD_USER_RELATION/ADD/REQUEST',
    ['WORD_USER_RELATION/ADD/SUCCESS', (res: WordUserRelationIndexDto) => res],
    ['WORD_USER_RELATION/ADD/FAILURE', (err: Error) => err],
    'WORD_USER_RELATION/ADD/CANCEL',
)();
const editActions = createAsyncAction(
    'WORD_USER_RELATION/EDIT/REQUEST',
    ['WORD_USER_RELATION/EDIT/SUCCESS', (res: WordUserRelationIndexDto) => res],
    ['WORD_USER_RELATION/EDIT/FAILURE', (err: Error) => err],
    'WORD_USER_RELATION/EDIT/CANCEL',
)();
const removeActions = createAsyncAction(
    'WORD_USER_RELATION/REMOVE/REQUEST',
    ['WORD_USER_RELATION/REMOVE/SUCCESS', (res: WordUserRelationIndexDto) => res],
    ['WORD_USER_RELATION/REMOVE/FAILURE', (err: Error) => err],
    'WORD_USER_RELATION/REMOVE/CANCEL',
)();
const removeGroupActions = createAsyncAction(
    'WORD_USER_RELATION/REMOVE_GROUP/REQUEST',
    ['WORD_USER_RELATION/REMOVE_GROUP/SUCCESS', (res: WordUserRelationIndexDto) => res],
    ['WORD_USER_RELATION/REMOVE_GROUP/FAILURE', (err: Error) => err],
    'WORD_USER_RELATION/REMOVE_GROUP/CANCEL',
)();


export type Actions = ActionType<typeof fetchActions>
    | ActionType<typeof setState>
    | ActionType<typeof initActions>
    | ActionType<typeof addActions>
    | ActionType<typeof editActions>
    | ActionType<typeof removeActions>
    | ActionType<typeof removeGroupActions>
    ;

export const fetch = (wordValue: string) =>
    async (dispatch: Dispatch) =>
        Axios.get<WordUserRelationDto>(`wordUserRelation/groups/${wordValue}`)
            .then(res => dispatch(fetchActions.success(res.data)))
            .catch(error => dispatch(fetchActions.failure(error)))

export const init = (wordValue: string) =>
    async (dispatch: Dispatch) =>
        Axios.post<WordGroupInitDto>(`wordUserRelation/init/${wordValue}`)
            .then(res => dispatch(initActions.success(res.data, wordValue)))
            .catch(error => dispatch(initActions.failure(error)))

export const add = (groupId: number, word: string, typeId: number, typeValue: string) =>
    async (dispatch: Dispatch) =>
        Axios.post<number>(`wordUserRelation/${groupId}/${word}/${typeId}`)
            .then(res => dispatch(addActions.success({
                id: res.data,
                typeId,
                word,
                groupId,
                typeValue,
            })))
            .catch(error => dispatch(addActions.failure(error)))

export const edit = (groupId: number, relationId: number, word: string, typeId: number, typeValue: string) =>
    async (dispatch: Dispatch) =>
        Axios.put(`wordUserRelation/${relationId}/${word}/${typeId}`)
            .then(_ => dispatch(editActions.success({
                id: relationId,
                typeId,
                word,
                groupId,
                typeValue,
            })))
            .catch(error => dispatch(editActions.failure(error)))

export const remove = (groupId: number, relationId: number) =>
    async (dispatch: Dispatch) =>
        Axios.delete<number>(`wordUserRelation/${relationId}`)
            .then(_ => dispatch(removeActions.success({
                id: relationId,
                typeId: -1,
                word: '',
                groupId,
                typeValue: '',
            })))
            .catch(error => dispatch(removeActions.failure(error)))

export const removeGroup = (groupId: number) =>
    async (dispatch: Dispatch) =>
        Axios.delete<number>(`wordUserRelation/groups/${groupId}`)
            .then(_ => dispatch(removeGroupActions.success({
                id: -1,
                typeId: -1,
                word: '',
                groupId,
                typeValue: '',
            })))
            .catch(error => dispatch(removeGroupActions.failure(error)))

const initialState: WordUserRelationState = {
    dto: {
        groupDtos: []
    }
};

export const Reducer = createReducer<WordUserRelationState, Actions>(initialState)
    .handleAction(setState, (_, action) => action.payload)
    .handleAction(fetchActions.success, (state, action) => {
        const newState = _.cloneDeep(state)
        newState.dto = action.payload
        return newState
    })
    .handleAction(initActions.success, (state, action) => {
        if (action.payload.word) {
            const newState = _.cloneDeep(state)
            newState.dto.groupDtos.push({
                relationDtos: [{
                    id: action.payload.relationId,
                    word: action.payload.word,
                    typeId: 1,
                    typeValue: '默认关系',
                }],
                id: action.payload.groupId
            })
            return newState
        }
        else {
            return state
        }

    })
    .handleAction(addActions.success, (state, action) => {
        const newState = _.cloneDeep(state)
        const i = _.findIndex(newState.dto.groupDtos, (groupDto) => groupDto.id === action.payload.groupId)
        newState.dto.groupDtos[i].relationDtos.push(action.payload)
        return newState
    })
    .handleAction(editActions.success, (state, action) => {
        const newState = _.cloneDeep(state)
        const i = _.findIndex(newState.dto.groupDtos, (groupDto) => groupDto.id === action.payload.groupId)
        const j = _.findIndex(newState.dto.groupDtos[i].relationDtos, (relationIdDto) => relationIdDto.id === action.payload.id)
        newState.dto.groupDtos[i].relationDtos[j] = action.payload
        return newState
    })
    .handleAction(removeActions.success, (state, action) => {
        const newState = _.cloneDeep(state)
        const i = _.findIndex(newState.dto.groupDtos, (groupDto) => groupDto.id === action.payload.groupId)
        _.remove(newState.dto.groupDtos[i].relationDtos, (relationIdDto) => relationIdDto.id === action.payload.id)
        return newState
    })
    .handleAction(removeGroupActions.success, (state, action) => {
        const newState = _.cloneDeep(state)
        _.remove(newState.dto.groupDtos, (groupDto) => groupDto.id === action.payload.groupId)
        return newState
    })
